package com.xc.core.utils;


import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.xc.core.config.*;
import com.xc.tool.utils.StringUtils;
import net.sf.json.JSONObject;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CreateUtil {


    public static void main(String[] args) {
        String projectPath = System.getProperty("user.dir") + "/AutoCreate";
        Config config = getConfig(projectPath + "/src/main/resources/config1.json");
        for (CreateConfig createConfig : config.getCreateConfig()) {
            create(createConfig, config);
        }
    }

    /**
     * 生成代码
     *
     * @param createConfig 创建模块配置
     * @param config       全局配置
     */
    private static void create(CreateConfig createConfig, Config config) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setAuthor(config.getAuthor());
        gc.setOpen(false);
        gc.setEntityName(createConfig.getModuleName() + "Entity");
        gc.setMapperName(createConfig.getModuleName() + "Mapper");
        gc.setIdType(IdType.ID_WORKER_STR);
        mpg.setGlobalConfig(gc);

        DataBaseConfig dataBaseConfig = config.getDataSource();

        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl(dataBaseConfig.getUrl());
        dsc.setDriverName(dataBaseConfig.getDriverName());
        dsc.setUsername(dataBaseConfig.getUsername());
        dsc.setPassword(dataBaseConfig.getPassword());
        // 数据源配置
        mpg.setDataSource(dsc);
        // 自定义配置
        mpg.setCfg(getTemplateConfig(createConfig, config));
        // 包配置
        PackageConfig pc = new PackageConfig();
        if (createConfig.getBackEnd() != null) {
            pc.setParent(createConfig.getBackEnd().getOutputWrap());
        }
        mpg.setPackageInfo(pc);
        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setService(null);
        templateConfig.setServiceImpl(null);
        templateConfig.setController(null);
        templateConfig.setMapper(null);
        templateConfig.setEntity(null);
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setSuperEntityColumns(config.getExcludeField());
        strategy.setInclude(createConfig.getTableName());
        strategy.setSuperEntityClass("com.xc.core.entity.ParentEntity");
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setEntityBooleanColumnRemoveIsPrefix(true);
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

    /**
     * 自定义配置
     *
     * @param createConfig 创建模块配置
     * @param config       全局配置
     * @return 模板配置
     */
    private static InjectionConfig getTemplateConfig(CreateConfig createConfig, Config config) {
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            //自定义属性注入:abc
            //在.ftl(或者是.vm)模板中，通过${cfg.abc}获取属性
            @Override
            public void initMap() {
                Map<String, Object> map = createConfig.getDataMap();
                if (map == null) {
                    map = new HashMap<>();
                }
                if (createConfig.getFrontEnd() != null) {
                    map.put("frontEndFileName", StringUtils.camelToUnderline(createConfig.getFrontEnd().getFileName()));
                }
                if (createConfig.getBackEnd() != null) {
                    map.put("backEndFileName", StringUtils.camelToUnderline(createConfig.getBackEnd().getFileName()));
                }
                map.put("name", createConfig.getModuleName());
                map.put("describe", createConfig.getDescribe());
                if (createConfig.getBackEnd() != null) {
                    map.put("data", createConfig.getBackEnd().getOutputWrap());
                }
                this.setMap(map);
            }
        };
        cfg.setFileOutConfigList(getFreemarker(createConfig, config));
        return cfg;
    }

    /**
     * 配置freemarker模板引擎
     *
     * @param createConfig 创建模块配置
     * @param config       全局配置
     * @return 配置集合
     */
    private static List<FileOutConfig> getFreemarker(CreateConfig createConfig, Config config) {
        BackEndConfig backEnd = createConfig.getBackEnd();
        List<FileOutConfig> focList = new ArrayList<>();
        if (backEnd != null) {
            String fileName = backEnd.getFileName();
            List<FileConfig> backEndFiles = config.getBackEndFiles();
            if (backEndFiles != null && backEndFiles.size() > 0) {
                for (FileConfig file : backEndFiles) {
                    if (!exist(createConfig.getNotCreates(), file.getFileType())) {
                        // 输出xml
                        focList.add(new FileOutConfig(file.getTemplatePath()) {
                            @Override
                            public String outputFile(TableInfo tableInfo) {
                                String path = backEnd.getProjectPath() + backEnd.getParentPath();
                                return path + file.getOutputPath() + "/" +
                                        fileName + file.getSuffix() + file.getFileSuffix();
                            }
                        });
                    }
                }
            } else {
                if (!exist(createConfig.getNotCreates(), "mapper-xml")) {
                    // 输出xml
                    focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
                        @Override
                        public String outputFile(TableInfo tableInfo) {
                            return backEnd.getProjectPath() + "/src/main/resources/mapper/" + fileName + "Mapper" + StringPool.DOT_XML;
                        }
                    });
                }
                if (!backEnd.getRelevance()) {
                    if (!exist(createConfig.getNotCreates(), "bean-java")) {
                        // 输出bean
                        focList.add(new FileOutConfig("/ftl/bean.java.ftl") {
                            @Override
                            public String outputFile(TableInfo tableInfo) {
                                return backEnd.getProjectPath() + "/src/main/java/" +
                                        backEnd.getOutputWrap().replace(".", "/") +
                                        "/bean/" + fileName + "Bean" + StringPool.DOT_JAVA;
                            }
                        });
                    }
                    if (!exist(createConfig.getNotCreates(), "dto-java")) {
                        // dto
                        focList.add(new FileOutConfig("/ftl/dto.java.ftl") {
                            @Override
                            public String outputFile(TableInfo tableInfo) {
                                return backEnd.getProjectPath() + "/src/main/java/" +
                                        backEnd.getOutputWrap().replace(".", "/") +
                                        "/dto/" + fileName + "Dto" + StringPool.DOT_JAVA;
                            }
                        });
                    }
                    if (!exist(createConfig.getNotCreates(), "rest-java")) {
                        // controller
                        focList.add(new FileOutConfig("/ftl/rest.java.ftl") {
                            @Override
                            public String outputFile(TableInfo tableInfo) {
                                return backEnd.getProjectPath() + "/src/main/java/" +
                                        backEnd.getOutputWrap().replace(".", "/") +
                                        "/rest/" + fileName + "Rest" + StringPool.DOT_JAVA;
                            }
                        });
                    }
                    if (!exist(createConfig.getNotCreates(), "service-java")) {
                        // service
                        focList.add(new FileOutConfig("/ftl/service.java.ftl") {
                            @Override
                            public String outputFile(TableInfo tableInfo) {
                                return backEnd.getProjectPath() + "/src/main/java/" +
                                        backEnd.getOutputWrap().replace(".", "/") +
                                        "/service/" + fileName + "Service" + StringPool.DOT_JAVA;
                            }
                        });
                    }
                    if (!exist(createConfig.getNotCreates(), "serviceImpl-java")) {
                        // serviceImpl
                        focList.add(new FileOutConfig("/ftl/serviceImpl.java.ftl") {
                            @Override
                            public String outputFile(TableInfo tableInfo) {
                                return backEnd.getProjectPath() + "/src/main/java/" +
                                        backEnd.getOutputWrap().replace(".", "/") +
                                        "/service/impl/" + fileName + "ServiceImpl" + StringPool.DOT_JAVA;
                            }
                        });
                    }
                }
                if (!exist(createConfig.getNotCreates(), "utils-java")) {
                    // utils
                    focList.add(new FileOutConfig("/ftl/utils.java.ftl") {
                        @Override
                        public String outputFile(TableInfo tableInfo) {
                            return backEnd.getProjectPath() + "/src/main/java/" +
                                    backEnd.getOutputWrap().replace(".", "/") +
                                    "/utils/ServiceUtils" + StringPool.DOT_JAVA;
                        }
                    });
                }
                if (!exist(createConfig.getNotCreates(), "mapper-java")) {
                    // mapper
                    focList.add(new FileOutConfig("/ftl/mapper.java.ftl") {
                        @Override
                        public String outputFile(TableInfo tableInfo) {
                            return backEnd.getProjectPath() + "/src/main/java/" +
                                    backEnd.getOutputWrap().replace(".", "/") +
                                    "/mapper/" + fileName + "Mapper" + StringPool.DOT_JAVA;
                        }
                    });
                }
                if (!exist(createConfig.getNotCreates(), "entity-java")) {
                    // entity
                    focList.add(new FileOutConfig("/ftl/entity.java.ftl") {
                        @Override
                        public String outputFile(TableInfo tableInfo) {
                            return backEnd.getProjectPath() + "/src/main/java/" +
                                    backEnd.getOutputWrap().replace(".", "/") +
                                    "/entity/" + fileName + "Entity" + StringPool.DOT_JAVA;
                        }
                    });
                }
            }
        }


        FrontEndConfig frontEnd = createConfig.getFrontEnd();
        if (frontEnd != null) {
            String fileName = StringUtils.camelToUnderline(frontEnd.getFileName());
            List<FileConfig> frontEndFiles = config.getFrontEndFiles();
            if (frontEndFiles != null && frontEndFiles.size() > 0) {
                for (FileConfig file : frontEndFiles) {
                    if (!exist(createConfig.getNotCreates(), file.getFileType())) {
                        // 输出xml
                        focList.add(new FileOutConfig(file.getTemplatePath()) {
                            @Override
                            public String outputFile(TableInfo tableInfo) {
                                return frontEnd.getProjectPath() + frontEnd.getParentPath() + file.getOutputPath() + "/" +
                                        fileName + file.getSuffix() + file.getFileSuffix();
                            }
                        });
                    }

                }
            } else {
                if (!exist(createConfig.getNotCreates(), "model-ts")) {
                    // 输出model
                    focList.add(new FileOutConfig("/ftl/model.ts.ftl") {
                        @Override
                        public String outputFile(TableInfo tableInfo) {
                            return frontEnd.getProjectPath() + frontEnd.getParentPath() + "/" + fileName + ".model.ts";
                        }
                    });
                }
                if (!exist(createConfig.getNotCreates(), "service-ts")) {
                    // 输出model
                    focList.add(new FileOutConfig("/ftl/service.ts.ftl") {
                        @Override
                        public String outputFile(TableInfo tableInfo) {
                            return frontEnd.getProjectPath() + frontEnd.getParentPath() + "/" + fileName + ".service.ts";
                        }
                    });
                }
            }
        }
        return focList;
    }


    /**
     * 是否存在
     *
     * @return false:不存在,true:存在
     */
    private static boolean exist(String[] types, String fileType) {
        if (types == null) {
            return false;
        }
        for (String type : types) {
            if (type.equals(fileType)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 获取json配置
     *
     * @param path json文件路径
     * @return 返回配置对象
     */
    private static Config getConfig(String path) {
        Config config = null;
        try {
            File file = new File(path);
            String json = FileUtils.readFileToString(file, "UTF-8");
            JSONObject jsonObject = new JSONObject().fromObject(json);
            Map<String, Class> classMap = new HashMap();
            classMap.put("createConfig", CreateConfig.class);
            classMap.put("backEndFiles", FileConfig.class);
            classMap.put("frontEndFiles", FileConfig.class);
            config = (Config) JSONObject.toBean(jsonObject, Config.class, classMap);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return config;
    }
}
